export const TouchType = {
    tap:'tap',
    swipe:'swipe',
    swipeleft:'swipeleft',
    swiperight:'swiperight',
    swipedown:'swipedown',
    swipeup:'swipeup',
    longtap:'longtap'
}
type ITouchType = keyof TouchType

export const supportTouch = ()=>{
    return !!(("ontouchstart" in window) 
    || window.navigator && window.navigator.msPointerEnabled && window.MSGesture 
    || window.DocumentTouch && document instanceof DocumentTouch)
}
export function getTouchEvents(){
    const touch= supportTouch()
    return {
        touchstart : touch?'touchstart':'mousedown',
        touchmove : touch?'touchmove':'mousemove',
        touchend : touch?'touchend':'mouseup'
    }
}
const touch = supportTouch()
const {touchstart,touchmove,touchend} = getTouchEvents()
    
export default class PhTouch{
    private target:HTMLElement;
    private type:ITouchType;
    private binding:any;
    private touches:{x:number,y:number};
    private thx:number;
    private thy:number
    private _moving:boolean;
    private _leaving: boolean;
    private _longtouch: boolean;
    private _stop : boolean
    private _timer = -1
    private callback:(e:Event)=>void

    constructor(el:HTMLElement,binding:any,type:ITouchType){
        this.thx = 10
        this.thy = 50
        this.target = el;
        this.binding = binding
        this.type = type
        this._moving = true
        this._leaving = true
        this._longtouch = false
        this._stop = binding.arg==="stop"
        this.callback = (e:Event,type?:ITouchType)=>{
            const cb = (typeof(binding.value)=="object"?binding.value.callback:binding.value) as (e:Event,type:ITouchType,v?:any)=>void
            if(typeof cb === "function")cb(e,type||this.type,this.binding.value)
        }

        this.target.addEventListener(touchstart,(e:TouchEvent)=>{
            this.start(e)
            if(this._stop){
                // e.stopImmediatePropagation()
                e.stopPropagation()
            }
        },false)
        this.target.addEventListener(touchmove,(e:TouchEvent)=>{
            this.move(e)
        },false)
        this.target.addEventListener(touchend,(e:TouchEvent)=>{
            this.end(e)
        },false)
    }
    private getEXY(e:any){
        const xy = touch?{x:e.changedTouches[0].pageX,y:e.changedTouches[0].pageY}:{x:e.pageX,y:e.pageY}
        return xy
    }
    private start(e:TouchEvent|MouseEvent){
        this.touches=this.getEXY(e);
        this._moving=true;
        this._leaving=true;
        this._longtouch=true;
        this._timer=setTimeout(()=>{
            if(this._leaving&&this._moving){
                this.type==TouchType.longtap&&this.callback(e);
                this._longtouch=false;
            }
        },1000);
    }
    private move(){
        this._moving = false
    }
    private end(e:TouchEvent|MouseEvent){
        const {thx,thy,_timer,touches,type,_longtouch,_moving} = this
        const {x,y} = this.getEXY(e)
        const disX=x-touches.x;
        const disY=y-touches.y;
        clearTimeout(_timer);
        if(Math.abs(disX)>thx||Math.abs(disY)>thy){
            type==TouchType.swipe&&this.callback(e)

            if(Math.abs(disX)>Math.abs(disY)){
                if(
                    (disX>thx&&type==TouchType.swiperight)||
                    (disX<-thx&&type==TouchType.swipeleft)
                )
                    this.callback(e)
            }else{
                if(
                    (disY>thy&&this.type==TouchType.swipedown)||
                    (disY<-thy&&this.type==TouchType.swipeup)
                )
                    this.callback(e)
            }
        }else{
            if(_longtouch&&_moving){
                type==TouchType.tap&&this.callback(e);
                this._leaving=false
            }
        }
    }
}